#pragma once
#ifndef __LIT__LIBRARY_MANAGER__HH__
#define __LIT__LIBRARY_MANAGER__HH__

#include <OgrePlatform.h>
#include <OgreDynLib.h>
#include <OgreDynLibManager.h>
#include "LitPrerequisites.h"
#include "LitExceptions.h"
#include "LitPointer.hpp"
#include "LitSingleton.hpp"

namespace Lit
{
	class LIT_API Library
	{
	public:
		typedef Ogre::DynLib	lib_t;
		typedef RefPtr<lib_t>	lib_ptr_t;
	protected:
		bool			mLoaded;
		lib_ptr_t		mHandle;
		String			mName;
	public:
		Library( const String &name, bool bload = true );
		virtual ~Library();
		bool isLoaded() const;
		void load( );
		void unload();
		const String &getName() const;

		template<typename FunctionPrototype>
		FunctionPrototype resolve( const String &name )
		{
			if( !mHandle ) throw ModuleException(mName, "cannot resolve function '"+name+"', library not loaded", EXC_LOC);
			FunctionPrototype sym = (FunctionPrototype)mHandle->getSymbol(name.str());
			
			if( !sym ) throw ModuleException(mName, "cannot resolve function '"+name+"', function not found", EXC_LOC);
			return sym;
		}
		lib_ptr_t handle() const;
	};

	typedef RefPtr<Library> LibraryPtr;

	class LIT_API LibraryManager : public Singleton<LibraryManager>
	{
	public:
		typedef std::map<std::string, LibraryPtr> Map;
		typedef Map::iterator iterator;
		typedef Map::const_iterator const_iterator;
	protected:
		Map mMap;

	public:
		LibraryManager();
		~LibraryManager();

		bool hasLibrary( const String &name ) const;
		LibraryPtr getLibrary( const String &name ) const;
		iterator begin();
		iterator end();
		const_iterator begin() const;
		const_iterator end()const;

		iterator findLibrary( const String &name );
		const_iterator findLibrary( const String &name )const;
		LibraryPtr load( const String &name );
		void unload( LibraryPtr &p );
	};
};

#endif